/******************************************************************
*
* Copyright 2010 Darshan M Sonde
*
* This file is part of ddots.
*
* ddots is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ddots is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ddots.  If not, see <http://www.gnu.org/licenses/>.
*
*********************************************************************/

#include <QtGui>
#include <QtDebug>
#include <QRadialGradient>
#include <QBrush>
#include <QColor>

#include "gamescene.h"
#include "dialog.h"
#include "game.h"
#include "rohmbus.h"


GameScene::GameScene(QObject *parent):
        QGraphicsScene(parent),
        mRow(5),
        mCol(5),
        mWon(false)
{
    setSceneRect(0,0,520,520); //some rand shape for default

    mPlayerOneStatus = new QGraphicsTextItem(PLAYER_ONE_TEXT);
    addItem(mPlayerOneStatus);
    mPlayerOneStatus->setPos(LEFTMARGIN,0);
    int statusHeight = QFontMetrics(mPlayerOneStatus->font()).height();

    mPlayerTwoStatus = new QGraphicsTextItem(PLAYER_TWO_TEXT);
    addItem(mPlayerTwoStatus);
    mPlayerTwoStatus->setPos(LEFTMARGIN,height()-statusHeight-TOPMARGIN);


    mBase = new QGraphicsRectItem(QRectF(0,0,width()-(LEFTMARGIN*2),height()-((TOPMARGIN+statusHeight)*2)));
    mBase->setPos(QPointF(LEFTMARGIN,TOPMARGIN+statusHeight));
    mBase->setBrush(QBrush(BGCOLOR));
    mBase->setPen(Qt::NoPen);
    addItem(mBase);

    connect(this,SIGNAL(boxComplete(QPoint)),this,SLOT(createBox(QPoint)));
    updatePlayerStatus();
}

void GameScene::setPlayerScore(Player player, int score)
{
    if(player==PlayerOne)
        mPlayerOneScore=score;
    else if(player==PlayerTwo)
        mPlayerTwoScore=score;
}

int GameScene::playerScore(Player player)
{
    if(player==PlayerOne)
        return mPlayerOneScore;
    else if(player==PlayerTwo)
        return mPlayerTwoScore;
    return 0;
}

void GameScene::clearGrid()
{
    qDeleteAll(mBoxElements);
    mBoxElements.clear();
    mBoxState.clear();

    foreach(Rohmbus *r,mRohmbusElements) {
        r->setOn(true);
    }

    mPlayerOneScore=0;
    mPlayerTwoScore=0;

    setWon(false);

    mCurrentTurn = PlayerOne;
}

/* assumes mRow, mCol, mLineWidth, mLineHeight are set. */
void GameScene::createGrid(int row,int col)
{
    mPlayerOneScore=0;
    mPlayerTwoScore=0;

    mRow=row;
    mCol=col;

    mLineWidth = (mBase->rect().width()/(mCol-1));
    mLineHeight = (mBase->rect().height()/(mRow-1));

    //delete entire grid    
    qDeleteAll(mRohmbusElements);
    mRohmbusElements.clear();    
    qDeleteAll(mBoxElements);
    mBoxElements.clear();
    qDeleteAll(mGridElements);    
    mGridElements.clear();


    for(int i=0;i<mRow;++i)
    {
        for(int j=0;j<mCol;++j)
        {
            int pointRadius = qMin(mBase->rect().width(),mBase->rect().height())/POINTSIZE;
            int x=j*mLineWidth- pointRadius;
            int y=i*mLineHeight- pointRadius;

            QGraphicsEllipseItem *e=new QGraphicsEllipseItem(mBase);
            e->setRect(QRectF(0,0,pointRadius*2,pointRadius*2));
            e->setBrush(QBrush(QColor(POINTCOLOR)));
            e->setPos(x,y); //mBase is parent so 0,0 already has margins
            e->setZValue(5);
            addElement(e);

            x += pointRadius;
            y += pointRadius;

            if( j != mCol-1 )
            {
                Rohmbus *r=new Rohmbus(mBase);
                r->setZValue(4);                
                r->setPen(Qt::NoPen);//DEBUG:r->setPen(QPen(Qt::green));

                QPolygonF polygon;
                polygon << QPointF(x,y)             << QPointF(x+(mLineWidth/2),y+(mLineHeight/2))
                        << QPointF(x+mLineWidth,y) << QPointF(x+(mLineWidth/2),y-(mLineHeight/2));
                r->setPolygon(polygon);
                r->setRowType(true);
                r->setStartPoint(QPoint(i,j));
                r->setEndPoint(QPoint(i,j+1));
                addElement(r);
                connect(r,SIGNAL(clicked(QPoint,QPoint)),this,SLOT(gotMove(QPoint,QPoint)));                
            }

            if( i != mRow-1 )
            {
                x -= mLineWidth/2;
                y += mLineHeight/2;
                Rohmbus *r=new Rohmbus(mBase);
                r->setZValue(4);                
                r->setPen(Qt::NoPen);//DEBUG:r->setPen(QPen(Qt::green));

                QPolygonF polygon;
                polygon << QPointF(x,y)             << QPointF(x+(mLineWidth/2),y+(mLineHeight/2))
                        << QPointF(x+mLineWidth,y) << QPointF(x+(mLineWidth/2),y-(mLineHeight/2));
                r->setPolygon(polygon);
                r->setRowType(false);
                r->setStartPoint(QPoint(i,j));
                r->setEndPoint(QPoint(i+1,j));
                addElement(r);
                connect(r,SIGNAL(clicked(QPoint,QPoint)),this,SLOT(gotMove(QPoint,QPoint)));
            }
        }
    }
}

void GameScene::createBox(QPoint leftTop)
{
    QGraphicsRectItem *rect=new QGraphicsRectItem(mBase);
    QRectF r(leftTop.y()*mLineWidth,leftTop.x()*mLineHeight,mLineWidth,mLineHeight);
    rect->setRect(r);

    if(mCurrentTurn==PlayerOne) {
        QRectF r=rect->rect();
        QLinearGradient gradient(r.topLeft(),r.bottomRight());//QRadialGradient gradient(r.center(),r.width()/2);
        gradient.setColorAt(0,PLAYER_ONE_GRADIENT_START);
        gradient.setColorAt(1,PLAYER_ONE_GRADIENT_END);
        rect->setBrush(QBrush(gradient));
    }
    else {
        QRectF r=rect->rect();
        QLinearGradient gradient(r.topLeft(),r.bottomRight());
        gradient.setColorAt(0,PLAYER_TWO_GRADIENT_START);
        gradient.setColorAt(1,PLAYER_TWO_GRADIENT_END);
        rect->setBrush(QBrush(gradient));
    }

    rect->setZValue(2);
    addElement(rect);

    //create text item also
    QGraphicsTextItem *text=new QGraphicsTextItem(rect);
    QString player;

    if(mCurrentTurn==PlayerOne)
        player=QString("1");
    else
        player=QString("2");
    text->setPlainText(player);

    QFont f(text->font());
    f.setPixelSize(qMin(r.width(),r.height())/2);
    text->setFont(f);
    QPointF c=r.center();
    QFontMetrics m(f);
    c-=QPointF(m.width(player)/2,m.height()/2);
    text->setPos(c);
    text->setZValue(4);
}

void GameScene::setTurn(Player player)
{
    mCurrentTurn = player;
    updatePlayerStatus();
}
Player GameScene::turn()
{
    return mCurrentTurn;
}

bool GameScene::selectLine(QPoint start, QPoint end)
{    
    foreach(Rohmbus *r,mRohmbusElements) {
        if((r->startPoint()==start) && (r->endPoint()==end)) {
            if(r->on()==false)
                return false;

            r->setOn(false);
            mBoxState[QLine(start,end)] = true;            
            updateBoxCompletions(start,end);            
            return true;
        }
    }
    return false;
}

void GameScene::setWon(bool won)
{
    mWon = won;
    updatePlayerStatus();
}

bool GameScene::won() { return mWon; }

void GameScene::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_O)
    {
        emit showDialog();
    }
}

void GameScene::gotMove(QPoint start, QPoint end)
{
    Q_ASSERT(!mBoxState.contains(QLine(start,end)));
    mBoxState[QLine(start,end)] = true;

    updateBoxCompletions(start,end);//emit boxComple if necessary
    updatePlayerStatus();
    emit lineSelected(start,end);
}
void GameScene::updateBoxCompletions(QPoint start, QPoint end)
{
    if(start.x()==end.x()) {
        //horizontal
        if(start.x()>0) {
            //above box
            QPoint aboveStart(start.x()-1,start.y());
            QPoint aboveEnd(end.x()-1,end.y());
            if(mBoxState.contains(QLine(aboveStart,aboveEnd))
                && mBoxState.contains(QLine(aboveStart,start))
                && mBoxState.contains(QLine(aboveEnd,end)))
                {
                //completes the above box
                incrementCurrentPlayerScore();
                emit boxComplete(aboveStart);
            }
        }
        if(start.x()<mRow) {
            //below
            QPoint belowStart(start.x()+1,start.y());
            QPoint belowEnd(end.x()+1,end.y());
            if(mBoxState.contains(QLine(start,belowStart))
                && mBoxState.contains(QLine(belowStart,belowEnd))
                && mBoxState.contains(QLine(end,belowEnd)))
                {
                //completes the below box
                incrementCurrentPlayerScore();
                emit boxComplete(start);
            }
        }
    } else {
        //vertical        
        if(start.y()>0) {
            //left
            QPoint leftStart(start.x(),start.y()-1);
            QPoint leftEnd(end.x(),end.y()-1);
            if(mBoxState.contains(QLine(leftStart,leftEnd))
                && mBoxState.contains(QLine(leftStart,start))
                && mBoxState.contains(QLine(leftEnd,end)))
                {
                //completes the above box
                incrementCurrentPlayerScore();
                emit boxComplete(leftStart);
            }
        }
        if(start.y()<mCol) {
            //below
            QPoint rightStart(start.x(),start.y()+1);
            QPoint rightEnd(end.x(),end.y()+1);
            if(mBoxState.contains(QLine(start,rightStart))
                && mBoxState.contains(QLine(rightStart,rightEnd))
                && mBoxState.contains(QLine(end,rightEnd)))
                {
                //completes the below box
                incrementCurrentPlayerScore();
                emit boxComplete(start);
            }
        }
    }
}

void GameScene::updatePlayerStatus()
{    
    QString turnStringOne = QString(" : Score %1").arg(mPlayerOneScore);
    QString turnStringTwo = QString(" : Score %1").arg(mPlayerTwoScore);;

    if(mWon) {
        if(mPlayerOneScore>mPlayerTwoScore) {
            turnStringOne += QString(" : ** WON ** ");
        } else if(mPlayerOneScore == mPlayerTwoScore) {
            turnStringOne += QString(" : ** DRAW **");
            turnStringTwo += QString(" : ** DRAW **");
        } else {
            turnStringTwo += QString(" : ** WON **");
        }
    }
    else {
        if(mCurrentTurn==PlayerOne) {
            turnStringOne += QString(" : TO PLAY");
        }else if(mCurrentTurn==PlayerTwo) {
            turnStringTwo += QString(" : TO PLAY");
        }
    }

    mPlayerOneStatus->setPlainText(QString("%1%2")
                                   .arg(PLAYER_ONE_TEXT)
                                   .arg(turnStringOne));
    mPlayerTwoStatus->setPlainText(QString("%1%2")
                                   .arg(PLAYER_TWO_TEXT)
                                   .arg(turnStringTwo));
}

void GameScene::incrementCurrentPlayerScore()
{
    if(mCurrentTurn==PlayerOne) {
        mPlayerOneScore++;
    } else if(mCurrentTurn==PlayerTwo) {
        mPlayerTwoScore++;
    }
}
